/*—————————————————————————————————————————————————————————— 公共方法文件 ——————————————————————————————————————————————————————————*/

import argon2 from 'argon2-wasm'
import { argon2Type, Base64EncryptionDecryption } from './interface'
import config from '@/common/config/config'

/**
 * @像素换算 用于获取此屏幕尺寸下对应的px值
 * @number 传入对应的rem值
 */
export const remToPx = (number: number): number => {
  // 如果能获取到根元素设置的fontsize
  let remSize =
    parseFloat(
      window?.getComputedStyle(document.documentElement)['fontSize']
    ) || 0
  // 未获取到根元素fontsize 则自己计算rem
  if (!remSize) {
    remSize = (1920 / document.body.clientWidth) * 192
  }
  // 依然未获取设置固定值
  if (!remSize) {
    remSize = 100
  }
  return Math.round(remSize * (number * 192)) / 192
}

/**
 * @随机数
 * @min 最小筛选值
 * @max 最大筛选值
 */
// -------------------------------------------------------------------------------------------------------------------------------
export const randomNum = (min: number, max: number) => {
  const range = max - min + 1
  const rand = Math.random()
  const num = min + Math.floor(rand * range)
  return num
}

/**
 * @数据深克隆方法_只针对数组或对象
 * @data传入需要深克隆的数据
 */
// -------------------------------------------------------------------------------------------------------------------------------
export const deepClone: <T>(data: T, json?: boolean) => T = (data, json) => {
  // 如果没有参数时，直接弹出并提示错误信息
  if (!data) {
    console.error('未存在深克隆参数')

    return

    // 判断是否开启了json深克隆模式的开关
  } else if (json) {
    // 是的话，直接进行弹出json好的属性
    return JSON.parse(JSON.stringify(data))
  }

  // 类型声明对象
  const dataStateArray = data instanceof Array
  const dataStateObject = data instanceof Object

  // 如果类型判断出不是数组或对象类型，则进行警告提示，并弹出此数据
  if (!dataStateArray && !dataStateObject) {
    console.warn('此参数不是对象或数组')
    return data
  }

  // 根据 data的数据类型，进行创建对应的深克隆原始类型
  const cloneData = dataStateArray ? [] : {}

  // 判断data是否是数组
  if (data instanceof Array) {
    // 是数组的话，进行循环遍历
    data.forEach((value, index) => {
      // 深克隆成员承接值
      let needValue: typeof value

      // 判断此成员是否是对象或者数组 是的话再次调用本方法
      value instanceof Object || value instanceof Array
        ? (needValue = deepClone(value))
        : (needValue = value)

      // 给对应的位置上进行赋值
      cloneData[index] = needValue
    })

    // 如果data是个对象
  } else if (data instanceof Object) {
    // 对对象进行遍历
    for (const key in data) {
      // 当前对应的data中的值
      const dataValue = data[key]
      // 后续数据承接值
      let needKeyValue: typeof dataValue
      // 判断当前在data中的值是什么类型，如果对象或数组的话，直接调用此方法，否则直接赋值
      dataValue instanceof Object || dataValue instanceof Array
        ? (needKeyValue = deepClone(dataValue))
        : (needKeyValue = dataValue)

      // 在深克隆数据承接对象中赋予对应的参数
      cloneData[key as unknown as string] = needKeyValue
    }
  }

  // 弹出最后的值
  return cloneData
}

/**
 * @内存处理类
 *
 * 全部的静态方法：
 * @getSession 访问回话存储成员 (传入查询的成员名称item；返回查询的成员值，若没有则是null)
 * @getBatchSession 批量访问回话存储成员 (传入查询的成员名称组成的string[]；返回查询的成员的键值对列表)
 * @setSession 设置回话存储成员 (传入修改的成员名称item、设置的值content)
 * @setBatchSession 批量设置回话存储成员 (传入修改的 成员名称name 和 设置值value 组成的对象列表)
 * @removeSession 删除回话存储成员 (传入删除的成员名称item)
 * @removeBatchSession 批量删除回话存储成员 (传入删除的成员名称组成的string[])
 * @getAllSession 访问全部回话存储 (返回目前回话存储中设置的所有成员集中对象)
 * @removeAllSession 删除全部回话存储
 *
 * @getLocal 访问长效存储成员 (传入查询的成员名称item；返回查询的成员值，若没有则是null)
 * @getBatchLocal 批量访问长效存储成员 (传入查询的成员名称组成的string[]；返回查询的成员的键值对列表)
 * @setLocal 设置长效存储成员 (传入修改的成员名称item、设置的值content)
 * @setBatchLocal 批量设置长效存储成员 (传入修改的 成员名称name 和 设置值value 组成的对象列表)
 * @removeLocal 删除长效存储成员 (传入删除的成员名称item)
 * @removeBatchLocal 批量删除长效存储成员 (传入删除的成员名称组成的string[])
 * @getAllLocal 访问全部长效存储 (返回目前长效存储中设置的所有成员集中对象)
 * @removeAllLocal 删除全部长效存储
 */
// -------------------------------------------------------------------------------------------------------------------------------
export class MemoryProcessing {
  // 回话存储处理
  // ==========================================================================================================================
  // 访问回话存储成员
  static getSession = (item: string) =>
    window.sessionStorage.getItem(item)
      ? JSON.parse(window.sessionStorage.getItem(item))
      : null

  // 批量访问回话存储成员
  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  static getBatchSession = (itemList: string[]) => {
    const needList = itemList.map((value) => {
      const itemValue = {}
      itemValue[value] = this.getSession(value)
      return itemValue
    })

    return needList
  }

  // 设置回话存储成员
  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  static setSession: <T>(item: string, content: T) => void = (item, content) =>
    window.sessionStorage.setItem(item, JSON.stringify(content))

  // 批量设置回话存储成员
  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  static setBatchSession = (
    itemList: Array<{ name: string; value: string }>
  ) => {
    itemList.forEach((value) => this.setSession(value.name, value.value))
  }

  // 删除回话存储成员
  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  static removeSession = (item: string) =>
    window.sessionStorage.removeItem(item)

  // 批量删除回话存储成员
  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  static removeBatchSession = (itemList: string[]) => {
    itemList.forEach((value) => this.removeSession(value))
  }

  // 访问全部回话存储
  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  static getAllSession = () => {
    // 内存数据承接对象
    const session = {}

    // 循环所有的回话存储的成员
    for (let index = 0; index < window.sessionStorage.length; index++) {
      // 获取到当前的内容key值
      const key = window.sessionStorage.key(index)

      // 给承接对象赋予解析后的真实值
      session[key] = this.getSession(key)
    }

    // 弹出处理好后的对象
    return session
  }

  // 删除全部回话存储
  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  static removeAllSession = () => window.sessionStorage.clear()

  // 长效存储处理
  // ==========================================================================================================================
  // 访问长效存储成员
  static getLocal = (item: string) =>
    window.localStorage.getItem(item)
      ? JSON.parse(window.localStorage.getItem(item))
      : null

  // 批量访问长效存储成员
  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  static getBatchLocal = (itemList: string[]) => {
    const needList = itemList.map((value) => {
      const itemValue = {}
      itemValue[value] = this.getLocal(value)
      return itemValue
    })

    return needList
  }

  // 设置长效存储成员
  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  static setLocal: <T>(item: string, content: T) => void = (item, content) =>
    window.localStorage.setItem(item, JSON.stringify(content))

  // 批量设置长效存储成员
  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  static setBatchLocal = (itemList: Array<{ name: string; value: string }>) => {
    itemList.forEach((value) => this.setLocal(value.name, value.value))
  }

  // 删除长效存储成员
  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  static removeLocal = (item: string) => window.localStorage.removeItem(item)

  // 批量删除长效存储成员
  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  static removeBatchLocal = (itemList: string[]) => {
    itemList.forEach((value) => this.removeLocal(value))
  }

  // 访问全部长效存储
  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  static getAllLocal = () => {
    // 内存数据承接对象
    const local = {}

    // 循环所有的回话存储的成员
    for (let index = 0; index < window.localStorage.length; index++) {
      // 获取到当前的内容key值
      const key = window.localStorage.key(index)

      // 给承接对象赋予解析后的真实值
      local[key] = this.getLocal(key)
    }

    // 弹出处理好后的对象
    return local
  }

  // 删除全部长效存储
  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  static removeAllLocal = () => window.localStorage.clear()
}

/**
 * @argon2加密
 *
 * @message 传入需要加密的字符串信息
 *
 * 返回加密后的数据对象
 */
// -------------------------------------------------------------------------------------------------------------------------------
export async function hashPassword(message: string): Promise<argon2Type> {
  try {
    const hash = await argon2.hash({
      pass: message,
      salt: config.encryptionSalt, // 加密的盐
      time: config.encryptionTime, // 以秒为单位的迭代次数
      mem: config.encryptionMem, // 以字节为单位的内存限制
      hashLen: config.encryptionHashLen, // 哈希结果的长度
      parallelism: config.encryptionParallelism, // 并行处理线程数
      type: config.encryptionType, // Argon2 算法类型
    })

    return hash as argon2Type
  } catch (err) {
    console.error('密码哈希错误：', err)
    return null
  }
}

/**
 * @前端base64编码加解密函数
 * @data 传入进行加解密的数据
 * @type 加密或解密 （1:加密，0:解密） 默认1
 */
// ------------------------------------------------------------------------------
export const base64EncryptionDecryption: Base64EncryptionDecryption = <T, U>(
  data: T,
  type = 1
) => {
  // 声明数据中转参数
  let transferParameters: U | string

  // 根据传入的type参数进行判断是加密还是解密
  switch (type) {
    case 1:
      // 加密时，先对data参数进行json字符串格式化，然后进行url编码转化，最后进行base64加密
      transferParameters = window.btoa(encodeURIComponent(JSON.stringify(data)))
      break

    case 0:
      // 解密时，先进行base64编码解密，然后进行url编码解密，然后进行Json还原
      transferParameters = JSON.parse(
        decodeURIComponent(window.atob(data as unknown as string))
      )
      break

    default:
      console.error(
        `type参数只能为数值1或0，请输入正确的type值，当前输入值为${type}`
      )
      break
  }

  // 弹出最后得到的中转参数
  return transferParameters
}
